Skip to content

🚀 Bytecode VM#93

Draft
timfennis wants to merge 188 commits intomasterfrom
feature/bytecode-vm
Draft

🚀 Bytecode VM#93
timfennis wants to merge 188 commits intomasterfrom
feature/bytecode-vm

Conversation

@timfennis
Copy link
Owner

@timfennis timfennis commented Mar 8, 2026

No description provided.

timfennis added 30 commits March 3, 2026 09:49
…layout

- Parser: stop wrapping VariableDeclaration in Statement; add it to
  is_valid_statement so the parse loop continues
- Compiler: split VariableDeclaration (push value only) from Assignment
  (push value + SetLocal + push unit); remove TODO comment
- VM: start with empty stack instead of pushing the script function,
  fixing local slot 0 conflicts that corrupted all local variables
- Tests: add test_declaration and test_assignment compiler tests
## Summary
- Remove `Expression::Index` from the AST — the parser now emits
`Expression::Call` with `"[]"` as the function name, consistent with how
binary operators (`+`, `-`, etc.) are already handled
- Register `[]` as a stdlib `GenericFunction` in
`ndc_stdlib/src/index.rs` that delegates to `get_at_index`
- Add `IndexError` custom error type and `value_to_evaluated_index` to
convert evaluated range values back to `EvaluatedIndex`
- Keep `Lvalue::Index` for assignment targets (`a[i] = val`) with
detection of `Call("[]")` pattern

## Test plan
- [x] All 230 program tests pass
- [x] All 15 compiler tests pass
- [x] Inclusive range without end (`a[0..=]`) correctly errors at parse
time
- [x] Slice with inverted bounds (`[0..7][3..2]`) returns proper error
instead of panicking
timfennis and others added 30 commits March 20, 2026 18:18
- B1: RangeInclusiveIter::size_hint overflowed when end == i64::MAX; use saturating_add
- B2: Return at top level caused usize underflow on frame_pointer - 1; guard with VmError
- B3: exec_unpack panicked on non-sequence values; return VmError for both cases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All WithVm HOFs call back closures via VmCallable::call -> call_callback,
which runs inline on the same VM stack. Open upvalue cells remain valid
after the arg drain because they reference the outer frame's stack slots,
not the arg slots. Materialization was only ever needed for call_function
(fresh VM, interpreter bridge) which no WithVm HOF uses.

Deleting the function and its call site fixes the shared-cell divergence
bug where inc and get capturing the same variable would disagree after a
HOF call. Adds reproducer bug0012 and design doc UPVALUE_DESIGN.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lloc, borrow candidates

- P3: replace close+retain two-pass with single retain_mut (~12% on closures bench)
- P4: inline shape/probe check before building vectorization_pairs Vec
- P5: borrow &[ResolvedVar] from stack instead of cloning Vec on every 2-arg dispatch
- R4: OverloadSet Hash+PartialEq now panic instead of silently misbehaving

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Value::matches_param now returns false immediately for typed container
params (List<T>, Deque<T>, Map<K,V>, Sequence<T>, Tuple) rather than
calling static_type().is_subtype() which iterated all elements. Adds
a troubleshooting doc explaining the dispatch behaviour and limitation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Also document map iteration semantics in the manual and add a
manual reference to CLAUDE.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
combinations() now returns a lazy iterator backed by a Vec<Value> pool
(eager drain for List/Tuple/Deque/Map, lazy buffering for Iterator sources).
Avoids materialising all combinations upfront; early exit never touches the
full pool. Also fixes a correctness bug where lazy sources could terminate
early when the pivot search saw only the buffered prefix.

Adds take(seq, n) — a lazy iterator yielding the first n elements of any
sequence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace run_str() with eval() returning Value instead of String
- Re-export Value and NativeFunction from ndc_interpreter
- Add Value::is_unit() helper
- Fix get_output() to return Some(vec![]) before first eval
- Remove ndc_lsp dependency on ndc_vm

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- M1: extract compile_for_iterations helper, removing ~120 lines of duplicated loop scaffolding
- M2: make VmIterator::deep_copy a required method; add missing impls for MinHeapIter, MaxHeapIter, StringIter
- RD1: comment explaining synthetic unit push in no-else branch
- RD2: remove dead `let memo =` binding in dispatch_call
- RD3: descriptive panic messages in Closure opcode handling
- RD4: rename max_local field to num_locals (matching its accessor)
- Remove REVIEW.md (all actionable items resolved)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…() builtin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ly-qualified Value paths

- Rename match.rs → types.rs with unified NdcType enum and classify() function
- Replace panics with syn::Error for proper compiler diagnostics
- Remove dead #[function] stub, add arg_error() and refcell_collection_arg() helpers
- Add module-level documentation to all macro crate files
- Update stdlib to use short Value/Object/SeqValue/MapValue imports everywhere

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n hot paths

- Merge MinHeapIter/MaxHeapIter into single HeapIter
- Merge List/Tuple unpack branches in VM
- Combine RangeInclusive/RangeExclusive compiler arms
- Inline vectorization_pairs into try_vectorized_call
- Use &OpCode references in Chunk::iter() and disassembler
- Cache Value::unit() via thread_local (9-16% faster on benchmarks)
- Minor: fix parens, rename shadowed param, update ndc_macros for HeapIter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…resolvers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…inition error

- Upvalues no longer short-circuit resolution: the scope walk continues
  to find exact matches for other overloads in parent scopes
- add_upvalue deduplicates by name+source so multiple overloads of the
  same function get separate upvalue entries
- Same-scope same-arity fn redefinition is now a compile error
- 9 new tests for shadowing/overloading semantics
- Updated manual with shadowing documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Function resolution now filters out bindings with known non-callable
types (Int, String, etc.) from the dynamic fallback, turning confusing
runtime errors into compile-time errors. Also tracks explicit `return`
types via a stack so `return value;` correctly infers the function's
return type instead of unit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… Any

return/break/continue now produce Never (bottom type) instead of
unit. Statement propagates Never so blocks see that control doesn't
fall through. This prevents `return 1;` from polluting the function's
return type with unit via lub.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… upvalues

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant